package com.wuzf.libannotation;

import com.alibaba.fastjson.JSONObject;
import com.google.auto.service.AutoService;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import javax.tools.FileObject;
import javax.tools.StandardLocation;


@AutoService(Process.class)
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({"com.wuzf.libannotation.ActivityDestination", "com.wuzf.libannotation.FragmentDestination"})
public class NavProcessor extends AbstractProcessor {

    private Messager messager;
    private Filer filer;
    private static final String FILE_NAME = "destination.json";

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        messager = processingEnv.getMessager();
        filer = processingEnv.getFiler();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> activityDestination = roundEnv.getElementsAnnotatedWith(ActivityDestination.class);
        Set<? extends Element> fragmentDestination = roundEnv.getElementsAnnotatedWith(FragmentDestination.class);

        if (!activityDestination.isEmpty() || !fragmentDestination.isEmpty()) {
            Map<String, JSONObject> destMap = new HashMap<>();
            builderDestination(activityDestination, ActivityDestination.class, destMap);
            builderDestination(fragmentDestination, FragmentDestination.class, destMap);

            // 将destMap写进文件中
            FileOutputStream fos = null;
            OutputStreamWriter osw = null;
            try {
                //filer.createResource()意思是创建源文件
                //我们可以指定为class文件输出的地方，
                //StandardLocation.CLASS_OUTPUT：java文件生成class文件的位置，/app/build/intermediates/javac/debug/classes/目录下
                //StandardLocation.SOURCE_OUTPUT：java文件的位置，一般在/ppjoke/app/build/generated/source/apt/目录下
                //StandardLocation.CLASS_PATH 和 StandardLocation.SOURCE_PATH用的不多，指的了这个参数，就要指定生成文件的pkg包名了
                FileObject resource = filer.getResource(StandardLocation.CLASS_OUTPUT, "", FILE_NAME);
                String path = resource.toUri().getPath();
                messager.printMessage(Diagnostic.Kind.NOTE, "path：" + path);
                String relativePath = path.substring(0, path.indexOf("app") + 4);
                messager.printMessage(Diagnostic.Kind.NOTE, "relativePath：" + relativePath);
                String assetsPath = relativePath + "src/main/assets/";
                messager.printMessage(Diagnostic.Kind.NOTE, "assetsPath：" + assetsPath);
                // 不存在这个文件夹则进行创建
                File file = new File(assetsPath);
                if (!file.exists()) {
                    file.mkdir();
                }
                // 存在这个文件则进行删除
                File outPutFile = new File(file, FILE_NAME);
                if (outPutFile.exists()) {
                    outPutFile.delete();
                }
                outPutFile.createNewFile();
                fos = new FileOutputStream(outPutFile);
                osw = new OutputStreamWriter(fos, "UTF-8");
                osw.write(JSONObject.toJSONString(destMap));
                osw.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (osw != null) {
                    try {
                        osw.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return true;
    }

    private void builderDestination(Set<? extends Element> elements,
                                    Class<? extends Annotation> annotation,
                                    Map<String, JSONObject> destMap) {
        for (Element element : elements) {
            Annotation anno = element.getAnnotation(annotation);
            //如果我们的注解标记在了类名上。所以可以直接强转一下。使用它得到全类名
            TypeElement typeElement = (TypeElement) element;
            //全类名com.mooc.ppjoke.home
            String clazName = typeElement.getQualifiedName().toString();
            //页面的id.此处不能重复,使用页面的类名做hascode即可
            int id = Math.abs(clazName.hashCode());
            String pageUrl = null;
            boolean isStart = false;
            boolean isLogin = false;
            boolean isActivity = false;
            if (anno instanceof ActivityDestination) {
                ActivityDestination destination = (ActivityDestination) anno;
                pageUrl = destination.pageUrl();
                isStart = destination.isStart();
                isLogin = destination.isLogin();
                isActivity = true;
            }

            if (anno instanceof FragmentDestination) {
                FragmentDestination destination = (FragmentDestination) anno;
                pageUrl = destination.pageUrl();
                isStart = destination.isStart();
                isLogin = destination.isLogin();
                isActivity = false;
            }

            if (destMap.get(pageUrl) != null) {
                // 说明已经存在此页面的信息
                messager.printMessage(Diagnostic.Kind.ERROR, "已经存在当前页面的数据");
            } else {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("id", id);
                jsonObject.put("pageUrl", pageUrl);
                jsonObject.put("isStart", isStart);
                jsonObject.put("isLogin", isLogin);
                jsonObject.put("isActivity", isActivity);
                jsonObject.put("className", clazName);
                destMap.put(pageUrl, jsonObject);
            }
        }
    }
}
